package com.zdj.aoplibrary.aspect;

import com.zdj.aoplibrary.annotations.DebugTrace;
import com.zdj.aoplibrary.util.DebugLog;
import com.zdj.aoplibrary.util.StopWatch;
import com.zdj.utils.LogLevel;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.ConstructorSignature;
import org.aspectj.lang.reflect.MethodSignature;

/**
 * 负责管理注解的处理和代码织入
 * 我们声明了两个作为 pointcuts 的 public 方法，筛选出所有通过 “com.zdj.aoplibrary.annotations.DebugTrace” 注解的方法和构造函数
 * Created by dengjie on 2016/01/08.
 */
@Aspect
public class TraceAspect {

    /**
     * 使用该注解的所有方法中使用{@link #POINTCUT_METHOD}逻辑 <br/>
     * modify by dengjie at 2016/01/08 21:32
     */
    private static final String POINTCUT_METHOD =
            "execution(@com.zdj.aoplibrary.annotations.DebugTrace * *(..))";

    /**
     * 使用该注解的所有方法中使用{@link #POINTCUT_CONSTRUCTOR}逻辑 <br/>
     * modify by dengjie at 2016/01/08 21:32
     */
    private static final String POINTCUT_CONSTRUCTOR =
            "execution(@com.zdj.aoplibrary.annotations.DebugTrace *.new(..))";


    @Pointcut(POINTCUT_METHOD)
    public void methodAnnotatedWithDebugTrace() {
    }

    @Pointcut(POINTCUT_CONSTRUCTOR)
    public void constructorAnnotatedDebugTrace() {
    }

    /**
     * 使用 “@Around” 注解定义了“weaveJointPoint(ProceedingJoinPoint joinPoint)”方法,使我们的代码注入在使用"@DebugTrace"注解的地方生效 <br/>
     * 作者 ：zdj <br/>
     * created at 16-6-25 上午8:30
     */
    @Around("methodAnnotatedWithDebugTrace() || constructorAnnotatedDebugTrace()")
    public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
        // 这里得判断是构造函数的注解还是方法的注解
        MethodSignature methodSignature = null;
        ConstructorSignature constructorSignature = null;
        if(joinPoint.getSignature() instanceof MethodSignature){
            methodSignature = (MethodSignature)joinPoint.getSignature();
        }else if(joinPoint.getSignature() instanceof ConstructorSignature){
            constructorSignature = (ConstructorSignature)joinPoint.getSignature();
        }
        String className = joinPoint.getSignature().getDeclaringType().getSimpleName();
        String methodName = joinPoint.getSignature().getDeclaringType().getName();

        final StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        // 被注解的方法执行的地方
        Object result = joinPoint.proceed();
        stopWatch.stop();
        /**
         * 获取注解的值
         * 默认为debug级别<br/>
         * modify by dengjie at 2016/01/08 21:06
         */
        DebugTrace debugTrace = null;
        if(methodSignature != null){
            debugTrace = methodSignature.getMethod().getAnnotation(DebugTrace.class);
        }
        if(constructorSignature != null){
            debugTrace = (DebugTrace)constructorSignature.getConstructor().getAnnotation(DebugTrace.class);
        }

        LogLevel level = debugTrace == null ? LogLevel.DEBUG : debugTrace.lever();
        DebugLog.log(level,className, buildLogMessage(methodName, stopWatch.getTotalTimeMillis()));
        return result;
    }




    /**
     * Create a log message.
     *
     * @param methodName     A string with the method name.
     * @param methodDuration Duration of the method in milliseconds.
     * @return A string representing message.
     */
    private static String buildLogMessage(String methodName, long methodDuration) {
        StringBuilder message = new StringBuilder();
        message.append("myLogUtil --> ");
        message.append(methodName);
        message.append(" --> ");
        message.append("[");
        message.append(methodDuration);
        message.append("ms");
        message.append("]");
        return message.toString();
    }
}
